﻿using System;
using System.ComponentModel.Composition;
using System.IO;
using System.Windows;
using System.ServiceModel.DomainServices.Client.ApplicationServices;
using System.Windows.Markup;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using GalaSoft.MvvmLight.Messaging;
using IssueVision.Common;
using IssueVision.Data.Web;
using MVVMPlugin;

namespace IssueVision.ViewModel
{
    [ExportPlugin(ViewModelTypes.MainPageViewModel, PluginType.ViewModel)]
    [PartCreationPolicy(CreationPolicy.NonShared)]
    public class MainPageViewModel : ViewModelBase
    {
        #region "Private Data Members"
        private IAuthenticationModel _authenticationModel;
        private IPasswordResetModel _passwordResetModel;
        private PluginCatalogService _catalogService;
        private LoginUser _currentUser;
        #endregion "Private Data Members"

        #region "Constructor"
        public MainPageViewModel()
        {
            _authenticationModel = PluginCatalogService.Container.GetExportedValue<IAuthenticationModel>();
            _passwordResetModel = PluginCatalogService.Container.GetExportedValue<IPasswordResetModel>();

            // set up PluginCatalogService
            _catalogService = PluginCatalogService.Instance;

            // set up event handling
            _authenticationModel.AuthenticationChanged += _authenticationModel_AuthenticationChanged;
            _authenticationModel.LogoutComplete += _authenticationModel_LogoutComplete;
            _authenticationModel.PropertyChanged += _authenticationModel_PropertyChanged;
            _passwordResetModel.PropertyChanged += _passwordResetModel_PropertyChanged;

            // call LoadUserAsync() to check whether authenticated or not
            _authenticationModel.LoadUserAsync();

            // set the initial values
            IsBusy = _authenticationModel.IsBusy || _passwordResetModel.IsBusy ||
                       ((IssueVisionModel == null) ? false : IssueVisionModel.IsBusy) ||
                       ((AdminIssueVisonModel == null) ? false : AdminIssueVisonModel.IsBusy);
            IsLoggedIn = _authenticationModel.User.Identity.IsAuthenticated;
            IsLoggedOut = !(_authenticationModel.User.Identity.IsAuthenticated);
            IsAdmin = _authenticationModel.User.IsInRole(IssueVisionServiceConstant.UserTypeAdmin);
            if (_authenticationModel.User.Identity.IsAuthenticated)
                WelcomeText = "Welcome " + _authenticationModel.User.Identity.Name;
            else
                WelcomeText = string.Empty;
            // set the initial theme selection
            IsBureauBlueTheme = true;
            IsExpressionLightTheme = false;
            IsShinyBlueTheme = false;
            IsTwilightBlueTheme = false;
            // set the current active screen
            CurrentScreenText = ViewTypes.HomeView;
        }
        #endregion "Constructor"

        #region "Public Properties"

        private IIssueVisionModel _issueVisionModel;

        [Import(AllowDefault=true, AllowRecomposition=true)]
        public IIssueVisionModel IssueVisionModel
        {
            get { return _issueVisionModel; }
            set
            {
                if (!ReferenceEquals(_issueVisionModel, value))
                {
                    if (_issueVisionModel != null)
                    {
                        _issueVisionModel.PropertyChanged -= IssueVisionModel_PropertyChanged;
                        if (value == null)
                        {
                            ICleanup cleanup = _issueVisionModel;
                            cleanup.Cleanup();
                        }
                    }
                    _issueVisionModel = value;
                    if (_issueVisionModel != null)
                    {
                        _issueVisionModel.PropertyChanged += IssueVisionModel_PropertyChanged;
                    }
                }
            }
        }

        private IAdminIssueVisionModel _adminIssueVisonModel;

        [Import(AllowDefault = true, AllowRecomposition = true)]
        public IAdminIssueVisionModel AdminIssueVisonModel
        {
            get { return _adminIssueVisonModel; }
            set
            {
                if (!ReferenceEquals(_adminIssueVisonModel, value))
                {
                    if (_adminIssueVisonModel != null)
                    {
                        _adminIssueVisonModel.PropertyChanged -= AdminIssueVisonModel_PropertyChanged;
                        if (value == null)
                        {
                            ICleanup cleanup = _adminIssueVisonModel;
                            cleanup.Cleanup();
                        }
                    }
                    _adminIssueVisonModel = value;
                    if (_adminIssueVisonModel != null)
                    {
                        _adminIssueVisonModel.PropertyChanged += AdminIssueVisonModel_PropertyChanged;
                    }
                }
            }
        }

        public bool HasChanges
        {
            get
            {
                return ((IssueVisionModel == null) ? false : IssueVisionModel.HasChanges) ||
                      ((AdminIssueVisonModel == null) ? false : AdminIssueVisonModel.HasChanges);
            }
        }

        private bool _isBusy;

        public bool IsBusy
        {
            get { return _isBusy; }
            private set
            {
                if (value != _isBusy)
                {
                    _isBusy = value;
                    RaisePropertyChanged("IsBusy");
                }
            }
        }

        private bool _isLoggedOut;

        public bool IsLoggedOut
        {
            get { return _isLoggedOut; }
            private set
            {
                if (value != _isLoggedOut)
                {
                    _isLoggedOut = value;
                    RaisePropertyChanged("IsLoggedOut");
                }
            }
        }

        private bool _isLoggedIn;

        public bool IsLoggedIn
        {
            get { return _isLoggedIn; }
            private set
            {
                if (value != _isLoggedIn)
                {
                    _isLoggedIn = value;
                    RaisePropertyChanged("IsLoggedIn");
                }
            }
        }

        private bool _isAdmin;

        public bool IsAdmin
        {
            get { return _isAdmin; }
            private set
            {
                if (value != _isAdmin)
                {
                    _isAdmin = value;
                    RaisePropertyChanged("IsAdmin");
                }
            }
        }

        private string _welcomeText;

        public string WelcomeText
        {
            get { return _welcomeText; }
            private set
            {
                if (!ReferenceEquals(_welcomeText, value))
                {
                    _welcomeText = value;
                    RaisePropertyChanged("WelcomeText");
                }
            }
        }

        private string _currentScreenText;

        public string CurrentScreenText
        {
            get { return _currentScreenText; }
            private set
            {
                if (!ReferenceEquals(_currentScreenText, value))
                {
                    _currentScreenText = value;
                    RaisePropertyChanged("CurrentScreenText");
                }
            }
        }

        private bool _isBureauBlueTheme;

        public bool IsBureauBlueTheme
        {
            get { return _isBureauBlueTheme; }
            private set
            {
                if (value != _isBureauBlueTheme)
                {
                    _isBureauBlueTheme = value;
                    RaisePropertyChanged("IsBureauBlueTheme");
                }
            }
        }

        private bool _isExpressionLightTheme;

        public bool IsExpressionLightTheme
        {
            get { return _isExpressionLightTheme; }
            private set
            {
                if (value != _isExpressionLightTheme)
                {
                    _isExpressionLightTheme = value;
                    RaisePropertyChanged("IsExpressionLightTheme");
                }
            }
        }

        private bool _isShinyBlueTheme;

        public bool IsShinyBlueTheme
        {
            get { return _isShinyBlueTheme; }
            private set
            {
                if (value != _isShinyBlueTheme)
                {
                    _isShinyBlueTheme = value;
                    RaisePropertyChanged("IsShinyBlueTheme");
                }
            }
        }

        private bool _isTwilightBlueTheme;

        public bool IsTwilightBlueTheme
        {
            get { return _isTwilightBlueTheme; }
            private set
            {
                if (value != _isTwilightBlueTheme)
                {
                    _isTwilightBlueTheme = value;
                    RaisePropertyChanged("IsTwilightBlueTheme");
                }
            }
        }

        #endregion "Public Properties"

        #region "Public Commands"

        private RelayCommand<Boolean> _logoutCommand;

        public RelayCommand<Boolean> LogoutCommand
        {
            get
            {
                if (_logoutCommand == null)
                {
                    _logoutCommand = new RelayCommand<Boolean>(
                        OnLogoutCommand);
                }
                return _logoutCommand;
            }
        }

        private void OnLogoutCommand(Boolean forceLogout)
        {
            try
            {
                if (!_authenticationModel.IsLoggingOut)
                {
                    if (!HasChanges)
                    {
                        // return back to the Home screen
                        AppMessages.ChangeScreenNoAnimationMessage.Send(ViewTypes.HomeView);
                        CurrentScreenText = ViewTypes.HomeView;
                        // then logout
                        _authenticationModel.LogoutAsync();
                    }
                    else
                    {
                        // there are pending changes
                        MessageBoxResult theResult = MessageBoxResult.Cancel;

                        if (forceLogout)
                        {
                            // if forceLogout is true, no need to ask for confirmation
                            theResult = MessageBoxResult.OK;
                        }
                        else
                        {
                            // ask to confirm canceling any pending changes
                            var dialogMessage = new DialogMessage(
                                this,
                                CommonResources.CancelAnyChangesMessageBoxText,
                                s => theResult = s)
                            {
                                Button = MessageBoxButton.OKCancel,
                                Caption = CommonResources.ConfirmMessageBoxCaption
                            };

                            AppMessages.PleaseConfirmMessage.Send(dialogMessage);
                        }

                        if (theResult == MessageBoxResult.OK)
                        {
                            // if confirmed, cancel any pending changes
                            if (IssueVisionModel != null) IssueVisionModel.RejectChanges();
                            if (AdminIssueVisonModel != null) AdminIssueVisonModel.RejectChanges();
                            // return back to the Home screen
                            AppMessages.ChangeScreenNoAnimationMessage.Send(ViewTypes.HomeView);
                            CurrentScreenText = ViewTypes.HomeView;
                            // then logout
                            _authenticationModel.LogoutAsync();
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                // notify user if there is any error
                AppMessages.RaiseErrorMessage.Send(ex);
            }
        }

        private RelayCommand<string> _changeThemeCommand;

        public RelayCommand<string> ChangeThemeCommand
        {
            get
            {
                if (_changeThemeCommand == null)
                {
                    _changeThemeCommand = new RelayCommand<string>(
                        OnChangeThemeCommand,
                        g =>
                            {
                                var themeResource = Application.GetResourceStream(
                                    new Uri("/IssueVision.Main;component/Assets/" + g, UriKind.Relative));
                                return themeResource != null;
                            });
                }
                return _changeThemeCommand;
            }
        }

        private void OnChangeThemeCommand(String g)
        {
            try
            {
                if (g == "BureauBlue.xaml" || g == "ExpressionLight.xaml" ||
                    g == "ShinyBlue.xaml" || g == "TwilightBlue.xaml")
                {
                    // remove the old one
                    Application.Current.Resources.MergedDictionaries.RemoveAt(Application.Current.Resources.MergedDictionaries.Count - 1);
                    // find and add the new one
                    var themeResource = Application.GetResourceStream(new Uri("/IssueVision.Main;component/Assets/" + g, UriKind.Relative));
                    var rd = (ResourceDictionary)(XamlReader.Load(new StreamReader(themeResource.Stream).ReadToEnd()));
                    Application.Current.Resources.MergedDictionaries.Add(rd);

                    // notify the change
                    if (g == "BureauBlue.xaml")
                    {
                        IsBureauBlueTheme = true;
                        IsExpressionLightTheme = false;
                        IsShinyBlueTheme = false;
                        IsTwilightBlueTheme = false;
                    }
                    else if (g == "ExpressionLight.xaml")
                    {
                        IsBureauBlueTheme = false;
                        IsExpressionLightTheme = true;
                        IsShinyBlueTheme = false;
                        IsTwilightBlueTheme = false;
                    }
                    else if (g == "ShinyBlue.xaml")
                    {
                        IsBureauBlueTheme = false;
                        IsExpressionLightTheme = false;
                        IsShinyBlueTheme = true;
                        IsTwilightBlueTheme = false;
                    }
                    else if (g == "TwilightBlue.xaml")
                    {
                        IsBureauBlueTheme = false;
                        IsExpressionLightTheme = false;
                        IsShinyBlueTheme = false;
                        IsTwilightBlueTheme = true;
                    }
                }
            }
            catch (Exception ex)
            {
                // notify user if there is any error
                AppMessages.RaiseErrorMessage.Send(ex);
            }
        }

        private RelayCommand<string> _changeScreenCommand;

        public RelayCommand<string> ChangeScreenCommand
        {
            get
            {
                if (_changeScreenCommand == null)
                {
                    _changeScreenCommand = new RelayCommand<string>(
                        OnChangeScreenCommand,
                        g => g != null);
                }
                return _changeScreenCommand;
            }
        }

        private void OnChangeScreenCommand(String g)
        {
            try
            {
                if (CurrentScreenText != g)
                {
                    if (!HasChanges)
                    {
                        // if no pending changes, switch to the new screen
                        switch (g)
                        {
                            case ViewTypes.HomeView:
                                // return back to the Home screen
                                AppMessages.ChangeScreenMessage.Send(ViewTypes.HomeView);
                                CurrentScreenText = ViewTypes.HomeView;
                                break;
                            case ViewTypes.NewIssueView:
                                // open the NewIssue screen
                                AppMessages.ChangeScreenMessage.Send(ViewTypes.NewIssueView);
                                CurrentScreenText = ViewTypes.NewIssueView;
                                break;
                            case ViewTypes.AllIssuesView:
                                // open the AllIssues screen
                                AppMessages.ChangeScreenMessage.Send(ViewTypes.AllIssuesView);
                                CurrentScreenText = ViewTypes.AllIssuesView;
                                break;
                            case ViewTypes.MyIssuesView:
                                // open the MyIssues screen
                                AppMessages.ChangeScreenMessage.Send(ViewTypes.MyIssuesView);
                                CurrentScreenText = ViewTypes.MyIssuesView;
                                break;
                            case ViewTypes.BugReportView:
                                // open the BugReport screen
                                AppMessages.ChangeScreenMessage.Send(ViewTypes.BugReportView);
                                CurrentScreenText = ViewTypes.BugReportView;
                                break;
                            case ViewTypes.MyProfileView:
                                // open the MyProfile screen
                                AppMessages.ChangeScreenMessage.Send(ViewTypes.MyProfileView);
                                CurrentScreenText = ViewTypes.MyProfileView;
                                break;
                            case ViewTypes.UserMaintenanceView:
                                // open the UserMaintenance screen
                                AppMessages.ChangeScreenMessage.Send(ViewTypes.UserMaintenanceView);
                                CurrentScreenText = ViewTypes.UserMaintenanceView;
                                break;
                            case ViewTypes.AuditIssueView:
                                // open the AuditIssue screen
                                AppMessages.ChangeScreenMessage.Send(ViewTypes.AuditIssueView);
                                CurrentScreenText = ViewTypes.AuditIssueView;
                                break;
                            default:
                                throw new NotImplementedException();
                        }
                    }
                    else
                    {
                        // there are pending changes
                        MessageBoxResult theResult = MessageBoxResult.Cancel;

                        // ask to confirm canceling any pending changes
                        var dialogMessage = new DialogMessage(
                            this,
                            CommonResources.CancelAnyChangesMessageBoxText,
                            s => theResult = s)
                        {
                            Button = MessageBoxButton.OKCancel,
                            Caption = CommonResources.ConfirmMessageBoxCaption
                        };

                        AppMessages.PleaseConfirmMessage.Send(dialogMessage);

                        if (theResult == MessageBoxResult.OK)
                        {
                            // if confirmed, cancel any pending changes
                            if (IssueVisionModel != null) IssueVisionModel.RejectChanges();
                            if (AdminIssueVisonModel != null) AdminIssueVisonModel.RejectChanges();
                            // and switch to the new screen
                            switch (g)
                            {
                                case ViewTypes.HomeView:
                                    // return back to the Home screen
                                    AppMessages.ChangeScreenMessage.Send(ViewTypes.HomeView);
                                    CurrentScreenText = ViewTypes.HomeView;
                                    break;
                                case ViewTypes.NewIssueView:
                                    // open the NewIssue screen
                                    AppMessages.ChangeScreenMessage.Send(ViewTypes.NewIssueView);
                                    CurrentScreenText = ViewTypes.NewIssueView;
                                    break;
                                case ViewTypes.AllIssuesView:
                                    // open the AllIssues screen
                                    AppMessages.ChangeScreenMessage.Send(ViewTypes.AllIssuesView);
                                    CurrentScreenText = ViewTypes.AllIssuesView;
                                    break;
                                case ViewTypes.MyIssuesView:
                                    // open the MyIssues screen
                                    AppMessages.ChangeScreenMessage.Send(ViewTypes.MyIssuesView);
                                    CurrentScreenText = ViewTypes.MyIssuesView;
                                    break;
                                case ViewTypes.BugReportView:
                                    // open the BugReport screen
                                    AppMessages.ChangeScreenMessage.Send(ViewTypes.BugReportView);
                                    CurrentScreenText = ViewTypes.BugReportView;
                                    break;
                                case ViewTypes.MyProfileView:
                                    // open the MyProfile screen
                                    AppMessages.ChangeScreenMessage.Send(ViewTypes.MyProfileView);
                                    CurrentScreenText = ViewTypes.MyProfileView;
                                    break;
                                case ViewTypes.UserMaintenanceView:
                                    // open the UserMaintenance screen
                                    AppMessages.ChangeScreenMessage.Send(ViewTypes.UserMaintenanceView);
                                    CurrentScreenText = ViewTypes.UserMaintenanceView;
                                    break;
                                case ViewTypes.AuditIssueView:
                                    // open the AuditIssue screen
                                    AppMessages.ChangeScreenMessage.Send(ViewTypes.AuditIssueView);
                                    CurrentScreenText = ViewTypes.AuditIssueView;
                                    break;
                                default:
                                    throw new NotImplementedException();
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                // notify user if there is any error
                AppMessages.RaiseErrorMessage.Send(ex);
            }
        }

        #endregion "Public Commands"

        #region "Private Methods"

        private void _authenticationModel_AuthenticationChanged(object sender, AuthenticationEventArgs e)
        {
            try
            {
                IsAdmin = e.User.IsInRole(IssueVisionServiceConstant.UserTypeAdmin);

                IsLoggedOut = !(e.User.Identity.IsAuthenticated);

                if (e.User.Identity.IsAuthenticated)
                {
                    WelcomeText = "Welcome " + e.User.Identity.Name;
                    // set _currentUser
                    _currentUser = (LoginUser)(e.User);

                    // load IssueVision.User.xap
                    _catalogService.AddXap("IssueVision.User.xap", arg => _issueVisionUserCompleted(arg));
                }
                else
                {
                    // unload IssueVision.User.xap
                    _catalogService.RemoveXap("IssueVision.User.xap");
                    // unload IssueVision.Admin.xap
                    _catalogService.RemoveXap("IssueVision.Admin.xap");
                    WelcomeText = string.Empty;
                    _currentUser = null;
                }
            }
            catch (Exception ex)
            {
                // notify user if there is any error
                AppMessages.RaiseErrorMessage.Send(ex);
            }
        }

        private void _issueVisionUserCompleted(System.ComponentModel.AsyncCompletedEventArgs e)
        {
            try
            {
                if (e.Error == null)
                {
                    if (IsAdmin)
                    {
                        // load IssueVision.Admin.xap next
                        _catalogService.AddXap("IssueVision.Admin.xap", arg => _issueVisionAdminCompleted(arg));
                    }
                    else
                    {
                        IsLoggedIn = !IsLoggedOut;
                        // if ProfileResetFlag is set
                        // ask the user to reset profile first                    
                        if ((_currentUser).ProfileResetFlag)
                        {
                            // open the MyProfile screen
                            AppMessages.ChangeScreenNoAnimationMessage.Send(ViewTypes.MyProfileView);
                            CurrentScreenText = ViewTypes.MyProfileView;
                        }
                        else
                        {
                            // otherwise, open the home screen
                            AppMessages.ChangeScreenNoAnimationMessage.Send(ViewTypes.HomeView);
                            CurrentScreenText = ViewTypes.HomeView;
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                // notify user if there is any error
                AppMessages.RaiseErrorMessage.Send(ex);
            }
        }

        private void _issueVisionAdminCompleted(System.ComponentModel.AsyncCompletedEventArgs e)
        {
            try
            {
                if (e.Error == null)
                {
                    IsLoggedIn = !IsLoggedOut;
                    // if ProfileResetFlag is set
                    // ask the user to reset profile first                    
                    if ((_currentUser).ProfileResetFlag)
                    {
                        // open the MyProfile screen
                        AppMessages.ChangeScreenNoAnimationMessage.Send(ViewTypes.MyProfileView);
                        CurrentScreenText = ViewTypes.MyProfileView;
                    }
                    else
                    {
                        // otherwise, open the home screen
                        AppMessages.ChangeScreenNoAnimationMessage.Send(ViewTypes.HomeView);
                        CurrentScreenText = ViewTypes.HomeView;
                    }
                }
            }
            catch (Exception ex)
            {
                // notify user if there is any error
                AppMessages.RaiseErrorMessage.Send(ex);
            }
        }

        private void _authenticationModel_LogoutComplete(object sender, LogoutOperationEventArgs e)
        {
            // even if e.HasError is True, we still set logout done.
            IsLoggedIn = false;
            IsLoggedOut = true;
            IsAdmin = false;
            _authenticationModel.LoadUserAsync();
        }

        private void _authenticationModel_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            switch (e.PropertyName)
            {
                case "IsBusy":
                    IsBusy = _authenticationModel.IsBusy || _passwordResetModel.IsBusy ||
                        ((IssueVisionModel == null) ? false : IssueVisionModel.IsBusy) ||
                        ((AdminIssueVisonModel == null) ? false : AdminIssueVisonModel.IsBusy);
                    break;
            }
        }

        private void _passwordResetModel_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            switch (e.PropertyName)
            {
                case "IsBusy":
                    IsBusy = _authenticationModel.IsBusy || _passwordResetModel.IsBusy ||
                        ((IssueVisionModel == null) ? false : IssueVisionModel.IsBusy) ||
                        ((AdminIssueVisonModel == null) ? false : AdminIssueVisonModel.IsBusy);
                    break;
            }
        }

        private void AdminIssueVisonModel_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            switch (e.PropertyName)
            {
                case "IsBusy":
                    IsBusy = _authenticationModel.IsBusy || _passwordResetModel.IsBusy ||
                        ((IssueVisionModel == null) ? false : IssueVisionModel.IsBusy) ||
                        ((AdminIssueVisonModel == null) ? false : AdminIssueVisonModel.IsBusy);
                    break;
            }
        }

        private void IssueVisionModel_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            switch (e.PropertyName)
            {
                case "IsBusy":
                    IsBusy = _authenticationModel.IsBusy || _passwordResetModel.IsBusy ||
                        ((IssueVisionModel == null) ? false : IssueVisionModel.IsBusy) ||
                        ((AdminIssueVisonModel == null) ? false : AdminIssueVisonModel.IsBusy);
                    break;
            }
        }

        #endregion "Private Methods"
    }
}
